package org.balthie.cal.impl.cmd;

import java.math.BigDecimal;
import java.util.Deque;
import java.util.Optional;

import org.balthie.cal.common.ex.CalculatorException;
import org.balthie.cal.common.spec.ISpecification;
import org.balthie.cal.core.ICommand;
import org.balthie.cal.impl.cmd.spec.ContainsCmdKindSpecs;
import org.balthie.cal.impl.cmd.spec.CurrentCmdSpecs;
import org.balthie.cal.impl.cmd.spec.PrevCmdTypeSpecs;

/**
 * @author：balthie@126.com
 * @createtime ： 2023年3月7日 下午1:37:55
 * @description “=”指令， 该指令会执行真实计算并打印计算结果
 * @since version 初始于版本 0.0.1-SNAPSHOT
 */
public class EqualsCmd extends GenericMathOptCmd {

	public EqualsCmd() {
		this(MathOperatorType.Equals);
	}

	@SuppressWarnings("unchecked")
	private EqualsCmd(MathOperatorType type) {
		super(type);
		// 当前新增输入是“=” 指令，并且包含运算符，并且运算符后面有数字 视为一个完整算式
		currentCmdSpecs = CurrentCmdSpecs.IS_MATHOPT_EQUALS;
		workAreaSpecs = ContainsCmdKindSpecs.CONTAINS_MATHOPT.and(PrevCmdTypeSpecs.IS_NUMB);
		// 不执行数学计算符通用规格验证
		this.legalSpecs = ISpecification.EMPTY_SPEC;
	}

	@Override
	public boolean isCompleted(Deque<ICommand> deque) {
		// 同时通过 指令集暂存区规格检查 + 当前新增指令规格检查
		return workAreaSpecs.isSatisfiedBy(deque)
				&& (currentCmdSpecs != null ? currentCmdSpecs.isSatisfiedBy(this) : Boolean.TRUE);
	}

	@Override
	public String getTips() {
		return "输出计算结果";
	}

	@Override
	public void execute(Deque<ICommand> workArea, Deque<ICommand> undoArea) {

		// 打印计算结果
		println("——————————————————————————————");
		print("算式显示栏|  ");
		workArea.stream().forEach(cmd -> print(cmd.getLiterally()));
		println();

		// 执行真实计算
		BigDecimal result = doMathcal(workArea);
		print("      =|  " + result);
		println();
		println("——————————————————————————————");

		// 完成计算后，清空工作区
		workArea.clear();
		undoArea.clear();
		println("本次计算完毕");
	}

	private MathOperatorType parseOpt(Deque<ICommand> deque) {
		Optional<ICommand> findFirst = deque.stream().filter(c -> CalKind.MathOperator == c.getCalKind()).findFirst();
		if (findFirst.isPresent()) {
			GenericMathOptCmd cmd = (GenericMathOptCmd) findFirst.get();
			return cmd.getOperator();
		}
		throw new CalculatorException("can not Retrieve the MathOperator ");
	}

	private BigDecimal parseRight(Deque<ICommand> deque) {
		StringBuilder numbs = new StringBuilder();
		// deque最后的指令要 拼接到numbs最后
		while (CalKind.LiterallyNumb == deque.getLast().getCalKind()) {
			numbs.append(deque.pollLast().getLiterally());
		}
		// right为空，视为0
		if (numbs.length() == 0)
			numbs.append("0");
		return new BigDecimal(numbs.reverse().toString());
	}

	private BigDecimal parseLeft(Deque<ICommand> deque) {
		StringBuilder numbs = new StringBuilder();
		while (CalKind.LiterallyNumb == deque.getFirst().getCalKind()) {
			numbs.append(deque.pollFirst().getLiterally());
		}
		// left为空，视为0
		if (numbs.length() == 0)
			numbs.append("0");
		return new BigDecimal(numbs.toString());
	}

	private BigDecimal doMathcal(Deque<ICommand> deque) {
		BigDecimal left = parseLeft(deque);
		BigDecimal right = parseRight(deque);
		MathOperatorType operator = parseOpt(deque);

		BigDecimal result;
		switch (operator) {
		case Add:
			result = left.add(right);
			break;
		case Subtract:
			result = left.subtract(right);
			break;
		case Multiply:
			result = left.multiply(right);
			break;
		case Divide:
			result = left.divide(right, 2, BigDecimal.ROUND_HALF_UP);
			break;
		default:
			result = new BigDecimal("0");
			break;
		}
		return result;
	}
}
